feat: ZS_Dead equivalent — death XP and loot init on NPC kill#375
feat: ZS_Dead equivalent — death XP and loot init on NPC kill#375BoroBongo wants to merge 7 commits into
Conversation
FightService.OnNpcDied() now replicates Gothic's ZS_Dead AI state logic: 1. Resets AIV_PLUNDERED to 0 (FALSE) on the dead NPC's instance 2. If EnableDeathXP and the killer is the hero: calls B_DeathXP via the Daedalus VM (sets XP, level, LP), then syncs results to hero.Vob via NpcService.SyncHeroInstanceToVob() 3. Always calls B_GiveDeathInv so the loot panel has items to show 4. Restores GlobalSelf / GlobalOther after both VM calls EnableDeathXP is gated behind EnableCombatSystem in DeveloperConfig and marked WIP (damage values are still debug stubs). Also adds EnableLevel5Cheat and EnableGuildCheat flags in DeveloperConfig (Misc / WIP section) used by StatusMenu cheat triggers.
|
Tested and now after killing NPC you'll see a change in the status menu. Killed diego and got a lot of levels 🗡️ |
| public bool EnableCombatSystem; | ||
|
|
||
| [ConditionalField(fieldToCheck: nameof(EnableCombatSystem), compareValues: true)] | ||
| [Tooltip("Call B_DeathXP on kill to grant XP. WIP - XP values may be incorrect.")] |
There was a problem hiding this comment.
Why does the value might be incorrect? Can you add it to be non-WIP? ;-)
|
|
||
| [ConditionalField(fieldToCheck: nameof(EnableCombatSystem), compareValues: true)] | ||
| [Tooltip("Call B_DeathXP on kill to grant XP. WIP - XP values may be incorrect.")] | ||
| public bool EnableDeathXP; |
There was a problem hiding this comment.
I don't think this needs to be guarded by a feature flag at all. Should do no harm to the game at runtime.
| if (target.Props.BodyState == VmGothicEnums.BodyState.BsDead) | ||
| return; | ||
|
|
||
| Logger.Log($"[FightService.OnHit] *** {attacker.Instance.GetName(NpcNameSlot.Slot0)} HIT {target.Instance.GetName(NpcNameSlot.Slot0)}", LogCat.Npc); |
There was a problem hiding this comment.
| Logger.Log($"[FightService.OnHit] *** {attacker.Instance.GetName(NpcNameSlot.Slot0)} HIT {target.Instance.GetName(NpcNameSlot.Slot0)}", LogCat.Fight); |
| } | ||
| } | ||
|
|
||
| var bGiveDeathInv = vm.GetSymbolByName("B_GiveDeathInv"); |
There was a problem hiding this comment.
Please use existing constants file for it:
Assets/Gothic-Core/Scripts/Const/DaedalusConst.cs
| var aivPlundered = vm.GetSymbolByName("AIV_PLUNDERED")?.GetInt(0) ?? 8; | ||
| dead.Instance.SetAiVar(aivPlundered, 0); | ||
|
|
||
| var oldSelf = vm.GlobalSelf; |
There was a problem hiding this comment.
Hm. We might have this more often to switch self/other to something different, then switch it back afterwards.
How about having a helper function as ZenKitExtension.cs but like GothicExtension.cs? With a function called ExchangeDaedalus() + ExchangeDaedalueBack() or so? Saves some back and forth code in the future?
| private void OnNpcDied(NpcContainer dead, NpcContainer killer) | ||
| { | ||
| var vm = _gameStateService.GothicVm; | ||
| var aivPlundered = vm.GetSymbolByName("AIV_PLUNDERED")?.GetInt(0) ?? 8; |
There was a problem hiding this comment.
Please put symbol into any of the *Constants. files.
|
|
||
| if (_configService.Dev.EnableDeathXP && killer.PrefabProps.IsHero()) | ||
| { | ||
| var bDeathXp = vm.GetSymbolByName("B_DeathXP"); |
| vob.Attributes[attributeId] = value; | ||
| } | ||
|
|
||
| public void SyncHeroInstanceToVob() |
There was a problem hiding this comment.
Hm. Why is it needed now?
I like it. It reminds me of the sync mechanism which is needed for the Save() logic. Why now? Or would it be sufficient to collect the data at save time?
FightService.OnNpcDied() now replicates Gothic's ZS_Dead AI state logic:
Enable DeathXP is gated behind EnableCombatSystem in DeveloperConfig and marked WIP (damage values are still debug stubs).
Also adds EnableLevel5Cheat and EnableGuildCheat flags in DeveloperConfig (Misc / WIP section) used by StatusMenu cheat triggers.